/*
 * Code de demarrage en C 
 * Recharge GDT et IDT 
 *
 */

/*========================================================================
 * Includes 
 *========================================================================*/

#include "klib.h"
#include "tables.h"
#include "start.h"

/*========================================================================
 * Macros 
 *========================================================================*/

#define MIN(_x,_y)     ((_x)<(_y)?(_x):(_y))
#define MAX(_x,_y)     ((_x)>(_y)?(_x):(_y))

/*========================================================================
 * Declarations Private 
 *========================================================================*/

PRIVATE u8_t start_e820_truncate32b(struct boot_info *bootinfo);

/*========================================================================
 * Fonction start_main
 *========================================================================*/

PUBLIC void start_main(struct boot_info *binfo)
{

	u8_t i;

	/* Initialise le port serie pour la sortie noyau */
	klib_serial_init();

	/* Recopie les informations de demarrage */
	bootinfo = binfo;

	/* Genere un memory map si besoins */
	/* no mem bank get by int 0x15 */
	if (!bootinfo->mem_map_count)
		goto err_mem;

	/* Tronque a 4G */
	if (start_e820_truncate32b(bootinfo) != EXIT_SUCCESS)
		goto err_mem;

	/* Calcul la memoire totale corrigee */
	bootinfo->mem_total = 0;
	for (i = 0; i < bootinfo->mem_map_count; i++) {
		struct boot_mmap_e820 *mmap = bootinfo->mem_map_addr;

		/* HACK TEST USER */
		if (mmap[i].size == 0x9F000)
			mmap[i].size = 0x9E000;

		klib_printf("BIOS mem map %d at %x size %x type %d\n",
				i, mmap[i].addr, mmap[i].size, mmap[i].type);

		bootinfo->mem_total += mmap[i].size;
	}
	klib_printf("Get available total mem %dKB\n", bootinfo->mem_total >> 10);
	klib_printf("Kernel start at %x end at %x\n", bootinfo->kern_start, bootinfo->kern_end);

	/* Initialise les tables du mode protege */
	if ((gdt_init() != EXIT_SUCCESS) || (idt_init() != EXIT_SUCCESS))
		goto err_tables;
	klib_printf("GDT & IDT initialized\n");

	return;

err_mem:
	klib_printf("Memory Error ! Aborting...\n");

err_tables:
	klib_printf("GDT & IDT Error\n");

	while (1) {
	}

	return;
}

/*========================================================================
 * Tronque la memoire a 4G dans un memory map trie
 *========================================================================*/

PRIVATE u8_t start_e820_truncate32b(struct boot_info * bootinfo)
{
	u8_t i;
	struct boot_mmap_e820 *mmap;

	mmap = (struct boot_mmap_e820 *)bootinfo->mem_map_addr;

	for (i = 0; i < bootinfo->mem_map_count; i++) {

		/* Marque la memoire au dela de 4G comme reservee */
		/* check addrH when mem bank over 4G */
		if ((mmap[i].addrH > 0)
		    && (mmap[i].type == START_E820_AVAILABLE)) {
			mmap[i].type = START_E820_RESERVED;
		}

	}

	return EXIT_SUCCESS;
}

